﻿using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PentaBiz.Collections.DataCache;

namespace PentaBiz.Testing.Collections.DataCache
{
    
    [TestClass]
    public class UnitTestSequentialDataCache
    {

        [TestMethod]
        [TestCategory("SequentialDataCache")]
        public void TestInitialize()
        {

            var c = SequentialDataCache<MyData>.Initialize(deleteOnClose: true);

            var path = c.Path;


            Assert.IsNotNull(c);

            c.Close();

            Assert.IsFalse(File.Exists(path));
        }

        [TestMethod]
        [TestCategory("SequentialDataCache")]
        public void TestIInitializeDeleteOnCloseFalse()
        {

            var c = SequentialDataCache<MyData>.Initialize(deleteOnClose: false);

            var path = c.Path;


            Assert.IsNotNull(c);

            c.Close();

            Assert.IsTrue(File.Exists(path));

            File.Delete(path);
        }

        [TestMethod]
        [TestCategory("SequentialDataCache")]
        public void TestAppendItem()
        {
            var path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".dat");

            var c = SequentialDataCache<MyData>.Initialize(deleteOnClose: true);

            var d = new MyData()
                        {
                            Id = Guid.NewGuid(),
                            TwoDimensionArray = new double[10, 10].InitializeArray(),
                        };
            c.Add(d);


            Assert.AreEqual(1, c.Count);

            c.Close();

            Assert.IsFalse(File.Exists(path));
        }

        [TestMethod]
        [TestCategory("SequentialDataCache")]
        public void TestAppendPerformance10000()
        {
            var path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".dat");

            var c = SequentialDataCache<MyData>.Initialize(path);

            for (int i = 0; i < 10000; i++)
            {
                var d = new MyData()
             {
                 Id = Guid.NewGuid(),
                 TwoDimensionArray = new double[10, 10].InitializeArray(),
             };
                c.Add(d);

            }



            Assert.AreEqual(10000, c.Count);

            c.Close();

            Assert.IsTrue(File.Exists(path));

            File.Delete(path);
        }


        [TestMethod]
        [TestCategory("SequentialDataCache")]
        public void TestAppendAndReadPerformance10000()
        {
            var path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".dat");

            var c = SequentialDataCache<MyData>.Initialize(path);

            for (int i = 0; i < 10000; i++)
            {
                var d = new MyData()
                {
                    Id = Guid.NewGuid(),
                    TwoDimensionArray = new double[3, 1000].InitializeArray(),
                };
                c.Add(d);

            }
            Assert.AreEqual(10000, c.Count);

            c.Close();




            var stopwatch = new Stopwatch();
            c = new SequentialDataCache<MyData>(path, deleteOnClose: true);
            stopwatch.Start();
            foreach (var myData in c)
            {

            }
            stopwatch.Stop();
            c.Close();


            Console.WriteLine("enumeration time: {0}", stopwatch.Elapsed);


            Assert.IsFalse(File.Exists(path));


            //File.Delete(path);
        }

        [TestMethod]
        [TestCategory("SequentialDataCache")]
        public void TestIfCanAppendMediumItemsPerformance10000()
        {
            var path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".dat");

            var c = SequentialDataCache<MyData>.Initialize(path, 10);

            for (int i = 0; i < 10000; i++)
            {
                var d = new MyData()
                {
                    Id = Guid.NewGuid(),
                    TwoDimensionArray = new double[3, 1000].InitializeArray(),
                };

                c.Add(d);
                //c.Add(d);

            }



            Assert.AreEqual(10000, c.Count);

            c.Close();

            Assert.IsTrue(File.Exists(path));
            File.Delete(path);

            Assert.IsFalse(File.Exists(path));
        }

        [TestMethod]
        [TestCategory("SequentialDataCache")]
        public void TestPerformanceAddItem10000()
        {
            using (var c = SequentialDataCache<MyData>.Initialize(deleteOnClose: true))
            {
                var sw = new Stopwatch();

                for (int i = 0; i < 10000; i++)
                {
                    var d = new MyData()
                 {
                     Id = Guid.NewGuid(),
                     TwoDimensionArray = new double[3, 1000].InitializeArray(),
                 };


                    sw.Start();
                    c.Add(d);
                    sw.Stop();
                }

                Console.WriteLine("Total time: {0}", sw.Elapsed);
                var unitTime = new TimeSpan(sw.Elapsed.Ticks / 10000);
                Console.WriteLine("Unit time: {0}", unitTime);
            }
        }
        [TestMethod]
        [TestCategory("SequentialDataCache")]
        public void TestPerformanceAddItem100000()
        {
            using (var c = SequentialDataCache<MyData>.Initialize(deleteOnClose: true))
            {
                var sw = new Stopwatch();

                for (int i = 0; i < 100000; i++)
                {
                    var d = new MyData()
                    {
                        Id = Guid.NewGuid(),
                        TwoDimensionArray = new double[3, 1000].InitializeArray(),
                    };


                    sw.Start();
                    c.Add(d);
                    sw.Stop();
                }

                Console.WriteLine("Total time: {0}", sw.Elapsed);
                var unitTime = new TimeSpan(sw.Elapsed.Ticks / 10000);
                Console.WriteLine("Unit time: {0}", unitTime);
            }
        }

        [TestMethod]
        [TestCategory("SequentialDataCache")]
        public void TestIfCanAppendMediumItemsPerformance100000()
        {
            var path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".dat");

            var c = SequentialDataCache<MyData>.Initialize(path, 10);

            for (int i = 0; i < 100000; i++)
            {
                var d = new MyData()
                {
                    Id = Guid.NewGuid(),
                    TwoDimensionArray = new double[3, 1000].InitializeArray(),
                };

                c.Add(d);

            }



            Assert.AreEqual(100000, c.Count);

            c.Close();

            Assert.IsTrue(File.Exists(path));
            File.Delete(path);

            Assert.IsFalse(File.Exists(path));
        }

        [TestMethod]
        [TestCategory("SequentialDataCache")]
        public void TestIfCanReReadSavedData()
        {
            var path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName() + ".dat");

            var c = SequentialDataCache<MyData>.Initialize(path, 10);

            for (int i = 0; i < 100; i++)
            {
                var d = new MyData()
                {
                    Id = Guid.NewGuid(),
                    TwoDimensionArray = new double[3, 1000].InitializeArray(),
                };

                c.Add(d);

            }



            Assert.AreEqual(100, c.Count);

            c.Close();

            c = new SequentialDataCache<MyData>(path);

            Assert.AreEqual(100, c.Count);
            foreach (var myData in c)
            {
                Assert.IsNotNull(myData);
                Assert.IsNotNull(myData.TwoDimensionArray);
                Assert.AreEqual(3 * 1000, myData.TwoDimensionArray.Length);
            }

            Assert.AreEqual(100, c.Count());


            c.Close();


            Assert.IsTrue(File.Exists(path));
            File.Delete(path);

            Assert.IsFalse(File.Exists(path));
        }

        [TestMethod]
        [TestCategory("SequentialDataCache")]
        public void TestIfCanSeekData()
        {

            var c = SequentialDataCache<MyData>.Initialize(10);
            var path = c.Path;

            for (int i = 0; i < 100; i++)
            {
                var d = new MyData()
                {
                    Id = Guid.NewGuid(),
                    TwoDimensionArray = new double[3, 1000].InitializeArray(),
                };

                c.Add(d);

            }



            Assert.AreEqual(100, c.Count);

            Assert.IsTrue(File.Exists(path));
            c.Close();
            Assert.IsTrue(File.Exists(path));

            c = new SequentialDataCache<MyData>(path);

            Assert.AreEqual(100, c.Count);

            var d0 = c[0];
            var d99 = c[99];


            c.Close();

            Assert.IsTrue(File.Exists(path));
            File.Delete(path);

            Assert.IsFalse(File.Exists(path));
        }

        [Serializable]
        class MyData
        {

            public MyData()
            {

            }



            public Guid Id { get; set; }
            //public double[][] JaggedArray { get; set; }
            public double[] OneDimensionArray { get; set; }
            public double[,] TwoDimensionArray { get; set; }
            public double[, ,] ThreeDimensionArray { get; set; }


            public static double[][] InitializeJaggedArray(int x = 3, int y = 1000)
            {
                var d = new double[x][];

                for (int i = 0; i < x; i++)
                {
                    d[i] = new double[y];
                    for (int j = 0; j < y; j++)
                        d[i][j] = i * j;
                }


                return d;
            }


        }
    }
}
